/**
 * Copyright (C) 2019-2021 杭州优诗科技有限公司
 *
 * This file is part of UnitSpirit.
 * @author wupingfu
 * @version 1.0.0
 * 
 **/
package com.unitspirit.sample.generics;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.List;

/**
 * @author wupf
 * 在Java里面可以通过反射获取泛型信息的场景有三个，分别是：

（1）成员变量的泛型

（2）方法参数的泛型

（3）方法返回值的泛型

注意，通过对象本身也是没法获取的。

不能通过发射获取泛型类型信息的场景有二个，分别是：

（1）类或接口声明的泛型信息

（2）局部变量的泛型信息
 *
 */
public class GenericUtil {

	public static void main(String[] args) {
		try {
			getMethodReturnType();
			getGenericFieldTypes();
			getMethodParameterTypes();
			getClassGeneric();
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	/**
	 * 
	 * @category 获取getStringList方法返回值的泛型类型
	 * @throws Exception
	 * @author wupf
	 * @Date :2021年4月13日下午12:44:39
	 */
	public static void getMethodReturnType() throws Exception {
		Method method = MyClass.class.getMethod("getStringList", null);
		System.out.println(method.getReturnType());
		Type retrunType = method.getGenericReturnType();
		System.out.println(retrunType);
		if (retrunType instanceof ParameterizedType) {
			ParameterizedType type = (ParameterizedType) retrunType;
			Type[] typeArguments = type.getActualTypeArguments();
			for (Type typeArgument : typeArguments) {
				Class typeArgClass = (Class) typeArgument;
				System.out.println("泛型类型：" + typeArgClass);
			}
		}
	}

	/**
	 * 
	 * @category 获取成员变量的泛型类型信息
	 * @throws Exception
	 * @author wupf
	 * @Date :2021年4月13日下午12:45:05
	 */
	public static void getGenericFieldTypes() throws Exception {
		Field field = MyClass.class.getField("stringList");
		Type genericsFieldType = field.getGenericType();
		if (genericsFieldType instanceof ParameterizedType) {
			ParameterizedType parameterizedType = (ParameterizedType) genericsFieldType;
			Type[] fieldArgTypes = parameterizedType.getActualTypeArguments();
			for (Type fieldArgType : fieldArgTypes) {
				Class fieldArgClass = (Class) fieldArgType;
				System.out.println("泛型字段的类型：" + fieldArgClass);
			}
		}
	}

	/**
	 * 
	 * @category 获取方法参数的泛型类型信息
	 * @throws Exception
	 * @author wupf
	 * @Date :2021年4月13日下午12:46:01
	 */
	public static void getMethodParameterTypes() throws Exception {
		Method method = MyClass.class.getMethod("setList", List.class);
		Type[] genericParameterTypes = method.getGenericParameterTypes();
		for (Type genericType : genericParameterTypes) {
			if (genericType instanceof ParameterizedType) {
				ParameterizedType parameterizedType = (ParameterizedType) genericType;
				Type[] types = parameterizedType.getActualTypeArguments();
				for (Type type : types) {
					Class realType = (Class) type;
					System.out.println("方法参数的类型：" + realType);
				}
			}
		}
		
	}
	
	/**
	 * 
	 * @category 获取类的泛型签名
	 * @return
	 * @author wupf
	 * @Date :2021年5月3日下午9:20:57
	 */
	public static String getClassGeneric() {
		//GenericClass2Test temp = new GenericClass<Double>();
		//System.out.println(Arrays.toString(temp.getClass().getTypeParameters()));
		
		GenericClass3 genericClass = new GenericClass3();
		System.out.println(Arrays.toString(genericClass.getClass().getTypeParameters()));
		Class clazz = genericClass.getClass();
		// getGenericSuperclass()获得带有泛型的父类
		// Type是Java中所有类型的公共高级接口,包括原始类型、参数化类型、数组类型、类型变量和基本类型。
		Type type = clazz.getGenericSuperclass();
		ParameterizedType p = (ParameterizedType)type;
		// getActualTypeArguments获取参数化类型的数组，泛型可能有多个
		Class c = (Class) p.getActualTypeArguments()[0];
		System.out.println(c);
		return c.getCanonicalName();
	}
}
